#pragma once
#include <stdint.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <vector>

/// \brief HeadCheckProtocol
/// \note: format: mrrb+(int32_t)len+data
/// \note: not thread safe
class HeadCheckProtocol
{
public:
    int32_t m_head = 0x6272726d;    //字符mrrb
    int32_t m_max_len = 1024*128;

    HeadCheckProtocol()
    {
       m_buff = nullptr;
       m_buff_len = 0;
       m_data_buff = malloc(m_max_len);
       m_data_buff_len = 0;
    }

    ~HeadCheckProtocol()
    {
        if (m_buff){
            free(m_buff);
        }
        free(m_data_buff);
    }

    /// \brief append data
    void append(const char* data, int32_t len)
    {
        if (m_buff_len > m_max_len) return;

        char *tmp_buff = malloc(m_buff_len + len);

        if (m_buff_len) {
            memcpy(tmp_buff, m_buff, m_buff_len);
            free(m_buff);
        }
        memcpy(tmp_buff+m_buff_len, data, len);
        m_buff_len += len;
        m_buff = tmp_buff;
    }

    /// \brief get data
    bool getData(char *data, int32_t &data_len)
    {
        if (m_buff_len > sizeof(m_head) + 4){
            int32_t *head = (int32_t *)m_buff;
            if (*head == m_head){
                int32_t len = *((int32_t *)(m_buff+4));
                if (len > m_max_len){
                    // error length clear buffer
                    free(m_buff);
                    m_buff_len = 0;
                }
                else {
                    if (m_buff_len >= sizeof(m_head) + 4 + len){
                        m_data_buff_len = len;
                        memcpy(m_data_buff, m_buff, sizeof(m_head) + 4 + len);

                        m_buff_len -= sizeof(m_head) + 4 + len;
                        char *tmp_buff = malloc(m_buff_len);
                        free(m_buff);
                        m_buff = tmp_buff;
                        data = m_data_buff;
                        len = m_data_buff_len;
                        return true;
                    }
                }
            }
        }
        return false;
    }

private:
    char *m_buff;               ///< buffer
    int32_t m_buff_len;         ///< buffer length
    char *m_data_buff;          ///< data buffer
    int32_t m_data_buff_len;    ///< data buffer len
};